package com.bluexmicro.ota2.ui.screen.config.bxlink

import android.bluetooth.BluetoothGattCharacteristic
import android.util.Log
import com.bluexmicro.bluetooth.peripheral.PeripheralManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentLinkedDeque

class MessageQueueManager(
    private val scope: CoroutineScope,
    private val onHandleMessage: suspend (message: BxLinkMessage) -> Boolean
) {

    private var peripheral: PeripheralManager.BluetoothPeripheral? = null
    private var handler: BluetoothGattCharacteristic? = null

    /**
     * 当前消息，如果消息为空时代表现在处于空闲状态，
     * 如果不为空代表正在发送消息-> 等待消息回应
     */
    private var currentMessage: BxLinkMessage? = null

    /**
     * ConcurrentLinkedDeque 是一个双端队列，可以在队列的两端添加和移除元素
     */
    private val deque = ConcurrentLinkedDeque<BxLinkMessage>()

    /**
     * 连接成功后
     */
    fun setup(
        peripheral: PeripheralManager.BluetoothPeripheral,
        characteristic: BluetoothGattCharacteristic
    ) {
        Log.d(
            "TAG",
            "setup() called with: peripheral = $peripheral, characteristic = $characteristic"
        )
        this.peripheral = peripheral
        this.handler = characteristic
    }

    fun onDisconnected() {
        deque.clear()
        this.currentMessage = null
        this.peripheral = null
        this.handler = null
        mJob?.takeIf { it.isActive }?.apply { cancel() }
    }

    fun pushMessage(
        msg: BxLinkMessage,
        highLevel: Boolean = false
    ) {
        if (highLevel) {
            deque.offerFirst(msg)
        } else {
            deque.offerLast(msg)
        }

        //空闲状态
        if (currentMessage == null && scope.isActive) {
            handleMessage()
        }
    }

    private var mJob: Job? = null
    private fun handleMessage() {
        Log.d("TAG", "handleMessage() called ${mJob?.isActive}")
        if (currentMessage != null || mJob?.isActive == true || deque.isNullOrEmpty()) return//已经有一个任务执行中，避免两个任务同时执行
        mJob = scope.launch {
            delay(100)
            // 再检查一遍currentMessage是否为空
            if (currentMessage == null && deque.isNotEmpty()) {
                // 从“栈顶”移除并返回元素
                currentMessage = deque.pop()
                val sent = onHandleMessage.invoke(currentMessage!!)
                if (sent) {
                    startTimeout()
                } else {
                    //当前消息出错，开始下一个
                    currentMessage = null
                    handleMessage()
                }
            }
        }
    }

    fun onError(msg: String) {
        currentMessage = null
        handleMessage()
    }

    fun onReceivedBxLinkMessage(message: BxLinkMessage) {
        //todo 对比收到的消息是否和当前的消息是否一致
        currentMessage = null
        cancelTimeout()
        handleMessage()
    }

    private var timeout: Job? = null
    private fun startTimeout() {
        cancelTimeout()
        timeout = scope.launch {
            delay(3000)
            if (timeout?.isActive == true) {
                currentMessage = null
                mJob?.takeIf { it.isActive }?.apply { cancel() }
            }
        }
    }

    private fun cancelTimeout() {
        timeout?.takeIf { it.isActive }?.apply { cancel() }
        mJob?.takeIf { it.isActive }?.apply { cancel() }
    }
}
